/*
MIT License 

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов, 

https://bmstu.codes/lsx/simodo/loom
*/

#ifndef simodo_interpret_host_fuze_ParsingTableBuilder_abstract
#define simodo_interpret_host_fuze_ParsingTableBuilder_abstract

/*! \file ParsingTableBuilder_abstract.h
    \brief Формирование структур грамматики по заданным правилам грамматики
*/

#include "simodo/inout/reporter/Reporter_abstract.h"
#include "simodo/parser/Grammar.h"

#include <string>
#include <map>
#include <set>


namespace simodo::interpret::builtins
{
    inline const size_t COLLISIONS_LIMIT = 20;


    /*!
     * \brief Класс формирование структур грамматики по заданным правилам грамматики
     *
     * Класс выполняет базовые подготовления для построения таблицы разбора по заданным правилам грамматики.
     * Является абстрактным классом.
     */
    class ParsingTableBuilder_abstract
    {
    protected:
        const inout::uri_set_t &                _files;
        inout::Reporter_abstract &              _m;             ///< Обработчик сообщений
        std::string                             _grammar_name;  ///< Наименование грамматики
        parser::Grammar &                       _g;             ///< Грамматика, которую нужно наполнить
        bool                                    _strict_rule_consistency; ///< Признак строгой проверки на согласованность правил

        std::vector<parser::GrammarRuleTokens>  _rules; ///< Правила
        std::multimap<std::u16string,size_t>    _production_index; ///< Индекс продукций для правил грамматики _rules
        std::multimap<std::u16string,size_t>    _pattern_index;    ///< Индекс символов из образца для правил грамматики _rules

        size_t                                  _number_of_collisions = 0;    ///< Счётчик несоответствий
        bool                                    _need_to_break        = false;

    public:
        virtual ~ParsingTableBuilder_abstract() = default;

        ParsingTableBuilder_abstract() = delete;    ///< Пустой конструктор не поддерживается!

        /*!
         * \brief Конструктор построителя таблицы разбора по заданной структуре правил грамматики
         * \param m             Интерфейсная ссылка на объект обеспечения вывода информации в вызываемую программу
         * \param grammar_name  Наименование грамматики, которую нужно загрузить
         * \param g             Структура грамматики
         * \param strict_rule_consistency Признак строгости в проверках согласованности таблицы разбора
         */
        ParsingTableBuilder_abstract(const inout::uri_set_t & files,
                                     inout::Reporter_abstract & m,
                                     const std::string & grammar_name,
                                     parser::Grammar & g,
                                     bool strict_rule_consistency)
            : _files(files)
            , _m(m)
            , _grammar_name(grammar_name)
            , _g(g)
            , _strict_rule_consistency(strict_rule_consistency)
        {}

        const inout::uri_set_t & files() const { return _files; }

        /*!
         * \brief Выполнение конструирования таблицы разбора
         *
         * Метод по заданному стартовому правилу вытягивает правила из заданного набора правил, помещая
         * их в структуру грамматики, заданную в конструкторе. Затем последовательно выполняет шаги и
         * проверки по построению таблицы разбора.
         *
         * \param rules     Контейнер с набором правил грамматики
         * \param main_rule Наименование стартового правила
         * \return          true, если построение завершилось успешно, иначе - false
         */
        bool    build(const std::vector<parser::GrammarRuleTokens> & rules, const inout::Token & main_rule);

        /*!
         * \brief Геттер признака строгой проверки на согласованность правил
         *
         * Данный признак нужен, если, например, нужно построить и проанализировать структуры таблицы разбора,
         * не взирая на некоторые несогласованности. Полезно, чтобы понять причину несогласованности.
         *
         * \return Признак строгой проверки на согласованность правил
         */
        bool    strict_rule_consistency() const { return _strict_rule_consistency; }

    protected:

        /*!
         * \brief Метод вытягивает по заданному стартовому правилу все связанные с ним правила из
         * заданного набора правил грамматики
         *
         * Метод вытягивает по заданному стартовому правилу все связанные с ним правила из
         * заданного набора правил грамматики и размещает их в структуре грамматики, переданной в конструкторе.
         *
         * \param rules      Контейнер с набором правил грамматики
         * \param production Наименование стартового правила
         * \return           true, если разбор завершился успешно, иначе - false
         */
        bool    extractRules(const std::vector<parser::GrammarRuleTokens> & rules, std::u16string production);

        /*!
         * \brief Наполнение контейнера с перечнем символов грамматики (колонок таблицы разбора)
         */
        void    fillColumns() const;

        /*!
         * \brief Проверка завершённости построения таблицы разбора
         * \return true, если проверка завершилась успешно, иначе - false
         */
        bool    checkCompleteness();

        /*!
         * \brief Метод построения таблицы состояний
         */
        virtual void fillStateTable() = 0;

        /*!
         * \brief Основной метод построения таблицы разбора по заполненным перечням состояний (строк)
         * и символов грамматики (колонок)
         * \return true, если формирование завершилось успешно, иначе - false
         */
        virtual bool fillParseTable() = 0;
    };

}

#endif // simodo_interpret_host_fuze_ParsingTableBuilder_abstract
